<?php

namespace app\mini\controller\salesman;

use app\common\enum\account\PaymentPayeeType;
use app\common\enum\order\OrderStatus;
use app\common\enum\order\OrderType;
use app\common\enum\order\PayeeType;
use app\common\enum\order\PayType;
use app\common\enum\order\ReasonType;
use app\common\enum\order\ReceiveType;
use app\common\exception\BaseException;
use app\common\model\AccountRecord;
use app\common\model\ReceiveLog;
use app\common\model\SalesmanDealer;
use app\common\model\SalesmanStore;
use app\common\service\annotation\ControllerAnnotation;
use app\common\service\annotation\NodeAnnotation;
use app\common\controller\ApiController;
use app\company\model\AccountPaymentRecord;
use app\company\model\CompanyOrder;
use app\common\model\Store;
use app\common\enum\mini\Settle as SettleEnum;
use app\common\enum\order\PayStatus;
use app\company\model\Payment;
use app\Request;
use think\App;
use think\response\Json;

/**
 * @ControllerAnnotation (title="收款")
 */
class Settle extends ApiController
{
    private Store $storeModel;
    private CompanyOrder $orderModel;

    public function __construct(App $app)
    {
        parent::__construct($app);
        $this->storeModel = new Store();
        $this->orderModel = new CompanyOrder();
    }

    public function storeList(): Json
    {
        $get = $this->request->get();
        // 接收参数
        if(!empty($get['lon']) && !empty($get['lat'])){
            $distance = distance($get['lon'],$get['lat']);
        }else{
            $distance = "'位置未知' AS distance";
        }
        $field = "*,{$distance}";
        $sql = $this->storeModel->field($field)->order('distance')->hasWhere('salesman', function ($query) {
            $query->field('balance')->where('salesman_id', $this->uid);
        });
        // 如果前端传参是应收门店列表，查询所有对应未结算订单的门店
        $where = [
            ['pid', '<>', 0],
            ['order_status', '=', OrderStatus::FINISH],
            ['order_type', '=', OrderType::SALES],
            ['receive_type', '=', ReceiveType::NOW],
            ['pay_status', '=', PayStatus::NOT_SETTLED],
            ['salesman_id', '=', $this->uid],
        ];
        if(!empty($get['type']) && $get['type'] == SettleEnum::TAKE) {
            $storeIds = $this->orderModel->where($where)->column('store_id');
            $sql->whereIn('id', array_unique($storeIds));
        }
        $whereStore = [];
        if(!empty($get['name'])){
            $whereStore[] = ['name','like','%'.$get['name'].'%'];
        }
        $paymentModel = new Payment();
        $list = $sql->where($whereStore)->paginate($get['limit']??15)->each(function ($item) use($where,$paymentModel) {
            $item->receive_money = $this->orderModel->where($where)->where('store_id', $item->id)->sum('unsay_amount');
            $item->should_payment = $paymentModel->where('store_id', $item->id)->where('pay_status',Payment::WAIT)->sum('money');
            $item->total_payment = $paymentModel->where('store_id', $item->id)->sum('money');
        });
        return $this->success($list);
    }

    /**
     * @NodeAnnotation (title="欠款订单列表")
     * @return Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function orderList(): Json
    {
        // 获取门店ID
        $get = $this->request->get();
        if(empty($get['store_id'])){
            return $this->error('参数缺失！');
        }
        $where = [
            ['pid', '<>', 0],
            ['order_status', '=', OrderStatus::FINISH],
            ['order_type', '=', OrderType::SALES],
            ['receive_type', '=', ReceiveType::NOW],
            ['pay_status', 'in', [PayStatus::NOT_SETTLED,PayStatus::HALF_SETTLED]],
            ['store_id', '=', $get['store_id']],
            ['unsay_amount', '>', 0],
        ];
        $data = [];
        $list = $this->orderModel->field('id,pid,order_status,order_type,receive_type,pay_status,order_no,unsay_amount,create_time')->with([
            'store' => function ($query) {
                $query->field('id,name');
            }
        ])->where($where)->select()->toArray();
        $data['list'] = $list;
        $data['num'] = count($list);
        $data['money'] = array_sum(array_column($list, 'unsay_amount'));
        return $this->success(compact('data'));
    }

    /**
     * @NodeAnnotation (title="欠款还款")
     * @param Request $request
     * @return Json
     */
    public function payOwe(Request $request): Json
    {
        $this->checkPost();
        $post = $request->post();
        if(empty($post['order_id'])) return $this->error('订单参数非法！');
        if(empty($post['money'])) return $this->error('金额参数非法！');
        try {
            $this->orderModel->transaction(function () use ($post) {
                // 修改订单数据
                $this->orderModel->where('id','in', $post['order_id'])->select()->each(function ($item) use(&$orderData){
                    $orderData[] = [
                        'id' => $item->id,
                        'pay_amount' => $item->delivery_amount,
                        'unsay_amount' => 0,
                        'pay_status' => PayStatus::SETTLED,
                        'update_time' => time(),
                    ];
                    $orderData[] = [
                        'id' => $item->pid,
                        'pay_amount' => $item->delivery_amount,
                        'unsay_amount' => 0,
                        'pay_status' => PayStatus::SETTLED,
                        'update_time' => time(),
                    ];
                });
                $this->orderModel->saveAll($orderData);
                // 组装支付信息
                $payData = [
                    'company_id' => $this->companyId,
                    'store_id' => $post['store_id'],
                    'payee_type' => PayeeType::SALESMAN,
                    'payee_id' => $this->uid,
                    'company_order_id' => $post['order_id'],
                    'company_order_pid' => '',
                    'pay_type' => $post['pay_type'],
                    'reason' => ReasonType::OWE,
                    'money' => $post['money'] ?? 0,
                    'image' => $post['image'] ?? '',
                    'remark' => $post['remark'] ?? '',
                    'create_time' => time(),
                    'update_time' => time(),
                ];
                $accountId = $this->addAccountPaymentRecord($post);
                $payData['account_record_id'] = $accountId;
                (new ReceiveLog())->save($payData);
            });
            return $this->success('还款成功');
        }catch (\Exception $e){
            return $this->success('还款失败');
        }
    }

    /**
     * @NodeAnnotation (title="预存款收款")
     * @param Request $request
     * @return Json
     */
    public function payBalance(Request $request): Json
    {
        $this->checkPost();
        $post = $request->post();
        if(empty($post['store_id'])) return $this->error('门店参数非法！');
        if(empty($post['money'])) return $this->error('金额参数非法！');
        try {
            $this->orderModel->transaction(function () use ($post) {
                // 记录收款日志
                $payData = [
                    'company_id' => $this->companyId,
                    'store_id' => $post['store_id'],
                    'payee_type' => PayeeType::SALESMAN,
                    'payee_id' => $this->uid,
                    'pay_type' => $post['pay_type'],
                    'reason' => ReasonType::YC,
                    'money' => $post['money'] ?? 0,
                    'image' => $post['image'] ?? '',
                    'remark' => $post['remark'] ?? '',
                    'create_time' => time(),
                    'update_time' => time(),
                ];
                (new SalesmanStore())->where('store_id', $post['store_id'])->where('salesman_id', $this->uid)
                    ->inc('balance', $post['money'])->save();
                $accountId = $this->addAccountPaymentRecord($post);
                $payData['account_record_id'] = $accountId;
                (new ReceiveLog())->save($payData);
            });
        }catch (\Exception $e){
            return $this->error('预存失败');
        }
        return $this->success('预存成功');
    }

    public function paymentList(): Json
    {
        $where = [];
        // 获取门店ID
        $get = $this->request->get();
        if(empty($get['store_id'])){
            return $this->error('参数缺失！');
        }
        if(!empty($get['pay_status'])){
            $where[] = ['pay_status', '=', $get['pay_status']];
        }else{
            $where[] = ['pay_status', '=', Payment::WAIT];
        }
        $dealerId = (new SalesmanDealer())->where('salesman_id',$this->uid)->column('dealer_id');
        $list = (new Payment())->with([
            'dealer' => function ($query) {
                $query->field('id,name');
            },
            'detail' => function ($query) {
                $query->with([
                    'companyOrder' => function ($query) {
                        $query->field('id,order_no');
                    }
                ]);
            },
        ])
            ->where('store_id',$get['store_id'])
            ->where('dealer_id','in',$dealerId)
            ->where($where)
            ->append(['pay_status_text','pay_type_text'])->select()->each(function ($item) {
                $item->order_num = count(explode(',',$item->company_order_ids));
            });
        return $this->success(compact('list'));
    }

    /**
     * @NodeAnnotation(title="支付账期")
     * @param Request $request
     * @return Json
     */
    public function payPay(Request $request): Json
    {
        if (!$request->isPost()) return $this->error('当前请求不合法！');
        $post = $request->post();
        if(empty($post['payment_ids'])) return $this->error('账期参数非法！');
        if(empty($post['pay_type'])) return $this->error('支付类型参数非法！');
        try {
            $this->orderModel->transaction(function () use ($post) {
                // 接收参数，拆分成多个账期，分开处理
                $paymentIds = explode(',',$post['payment_ids']);
                array_walk($paymentIds,function ($v) use ($post){
                    $payment = (new Payment())->where('id',$v)->find();
                    if($payment->pay_status != Payment::WAIT) throw new BaseException(['message' => '该账期已支付，请勿重复支付！']);
                    // 组装支付信息
                    $payData = [
                        'company_id' => $this->companyId,
                        'store_id' => $payment->store_id,
                        'payee_type' => PayeeType::SALESMAN,
                        'payee_id' => $this->uid,
                        'company_order_id' => $payment->company_order_ids,
                        'pay_type' => $post['pay_type'],
                        'reason' => ReasonType::ZQ,
                        'money' => $payment->money ?? 0,
                        'image' => $post['image'] ?? '',
                        'remark' => $post['remark'] ?? '',
                    ];
                    $companyOrderIds = explode(',',$payment->company_order_ids);
                    array_walk($companyOrderIds,function ($v) use ($payment){
                        $info = (new CompanyOrder())->where('id',$v)->find();
                        $info->save(['pay_status' => PayStatus::SETTLED,'pay_amount' => $info->delivery_amount,'unsay_amount' => 0]);
                    });
                    // 修改账期单状态
                    $payment->save(['pay_status' => Payment::SUCCESS,'payee_type'=>1,'payee_id'=>$this->uid,'payee_time' => time()]);
                    $post['store_id'] = $payment->store_id;
                    $post['money']    = $payment->money;
                    $accountId = $this->addAccountPaymentRecord($post);
                    $payData['account_record_id'] = $accountId;
                    (new ReceiveLog())->save($payData);
                });
            });
            return $this->success('支付成功');
        }catch (\Exception $e){
            return $this->error('支付失败');
        }
    }

    /**
     * 生成收款单列表明细
     */
    private function addAccountPaymentRecord(mixed $post): mixed
    {
        // 生成对账单数据
        $accountModel = new AccountRecord();
        $accountInfo  = $accountModel->where('company_id', $this->companyId)
            ->where('payee_type', AccountRecord::SALESMAN)
            ->where('payee_id', $this->uid)->find();$submitMoney  = $checkMoney = 0;
        if ($post['pay_type'] == PayType::CASH) {
            $submitMoney = $post['money'];
        } else {
            $checkMoney = $post['money'];
        }
        if (!$accountInfo) {
            $accountData = [
                'company_id'   => $this->companyId,
                'payee_type'   => AccountRecord::DRIVER,
                'payee_id'     => $this->uid,
                'total_money'  => $post['money'],
                'real_money'   => 0,
                'submit_money' => $submitMoney,
                'check_money'  => $checkMoney,
            ];
            $accountModel->save($accountData);
            $accountId = $accountModel->getKey();
        } else {
            $accountInfo->inc('total_money', $post['money'])->inc('submit_money', $submitMoney)
                ->inc('check_money', $checkMoney)->save();
            $accountId = $accountInfo->id;
        }
        if ($post['pay_type'] == PayType::BANK) {
            (new AccountPaymentRecord())->save([
                                                       'no'         => generateOrderNo('SK'),
                                                       'company_id' => $this->companyId,
                                                       'account_id' => $accountId,
                                                       'payee_type' => PaymentPayeeType::SALES,
                                                       'payee_id'   => $this->uid,
                                                       'store_id'   => $post['store_id'],
                                                       'amount'     => $post['money'],
                                                       'channel'    => '公司账户款项',
                                                       'pay_type'   => PayType::BANK,
                                                       'remark'     => $post['remark'] ?? '',
                                                       'voucher'    => $post['image'] ?? '',
                                               ]);
        }
        return $accountId;
    }
}